fix(claude): keep at-limit claude-swap cards complete - #3081
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
|
🦞👀 Pull request received. I will update this pull request when review starts. |
Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c1334b2704
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Project usage only for ok and unavailable slots, and retain a previous snapshot only when the email still matches and a 100% window has not reset. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Codex review: needs real behavior proof before merge. Reviewed August 20, 2026, 1:05 AM ET / 05:05 UTC. ClawSweeper reviewWhat this changesThe PR retains Claude Swap at-limit usage windows across deferred polling and renders the retained bars plus reset notes in the app, CLI cards, and dashboard. Merge readiness⛔ Blocked until stronger real behavior proof is added - 9 items remain Keep open: current main still drops unavailable Claude Swap usage, but this branch needs real deferred-polling proof and resolution of two persistent-cache safety defects before merge. Priority: P2 Review scores
Verification
How this fits togetherClaude Swap list responses are projected into CodexBar account usage snapshots, which feed menu cards, terminal cards, and the dashboard. This PR adds a retained-window cache so an unavailable response can continue to show an exhausted rate-limit state. flowchart LR
A[Claude Swap list response] --> B[Usage projection]
B --> C{Usage unavailable?}
C -->|no| D[Current account snapshot]
C -->|yes| E[Retained rate-window cache]
D --> F[Menu, CLI, and dashboard cards]
E --> F
Decision needed
Why: The restart-survival feature requires a durable account binding, but the available binding is privacy-sensitive and still conflates organization accounts that share an email. Before merge
Findings
Agent review detailsSecurityNeeds attention: The patch adds a persistent, deterministic email-derived identifier without a protected storage boundary. Review metrics
Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Use a non-email, source-issued opaque account discriminator for any restart-persistent cache; otherwise keep retention in memory, add same-email replacement coverage, and provide a redacted after-fix unavailable-path transcript. Do we have a high-confidence way to reproduce the issue? Yes, from source: current main projects only Is this the best way to solve the issue? No: retaining at-limit windows is appropriate, but a durable cache must not rely on an email-derived discriminator that can both leak correlation and collide for same-email organizations. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 61f542253c65. LabelsLabel justifications:
EvidenceSecurity concerns:
What I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (9 earlier review cycles; latest 8 shown)
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d994ed18dd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
steipete
left a comment
There was a problem hiding this comment.
The direction is right (an at-limit deferral is current truth, not a stale fetch failure), but the PR's own test fails on its own head, before any interaction with main:
✘ "unavailable refresh retains previous at limit snapshot"
account.snapshot?.primary?.usedPercent → nil, expected 100
account.snapshot?.secondary?.usedPercent → nil, expected 100
account.snapshot?.updatedAt → nil, expected now
error → "Polling deferred until a limit resets." (expected to name the exhausted windows)
Reproduced locally at d994ed1 with swift test --filter ClaudeProviderRuntimeTests. The projection returns no snapshot for the usageStatus: "unavailable" + usage: null row in the runtime path, so the retained-snapshot behavior the PR describes isn't reaching account.snapshot — only the projection-level unit tests pass. Looks like the runtime refresh path (UsageStore+ClaudeSwapRefresh) still drops the row before your retention logic runs.
I've merged current main into the branch (pushed) so you're up to date. Once the runtime path retains the snapshot and the suite is green on your side, ping me and I'll land it — #3082 (alias disambiguation) can go in the same pass since it's stacked on the same area.
Keeping the whole previous snapshot after any sibling reset still showed "Resets now" on lanes that had already recovered. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0e4c0f4162
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
One-shot cards and dashboard now reuse the last slot windows so an unavailable cswap row with null usage keeps the exhausted bars. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 18d66cc92c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
A SHA-256 fingerprint in the retained-usage cache rejects leftover 100% bars after the same slot is reused by a different account. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 38882c3248
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Direct cswap unavailable payloads with mixed reset times now drop already-reset lanes the same way retained snapshots do. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 425da0b7ce
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Seed the app projection from the retained-usage cache after a relaunch, and render dashboard windows alongside the deferred/limit note instead of returning after the error. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 25b06a8c6c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 87a909112b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Slot-only fingerprints reused bars after an email-less account was replaced. Decline persistence and reuse unless the row has an email, and move the changelog note to 0.54.1 Unreleased. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1f60407982
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Stale claude-swap refreshes were writing the on-disk cache before the generation guard, and 100% windows without a future reset were kept forever. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e0e8c48321
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…tails SwiftFormat rejected the nested guard wrap, and OpenRouter detail titles now follow the steipete#3084 localization pass. Co-authored-by: Cursor <cursoragent@cursor.com>
A non-exhausted session lane with no resetsAt was kept beside a weekly at-limit bar and re-saved until that weekly reset, so a five-hour value could linger for days. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
Summary
cswap --list --jsonreportsusageStatus: "unavailable"withusage: null. CodexBar previously dropped the snapshot and showed a red empty card: "Usage fetch failed."Final behavior
.okor.unavailable(defensive; current cswap 0.22.0 still sendsusage: nullwithunavailable)..unavailablewith no windows, retain that slot's previousProviderAccountUsageSnapshot.snapshotfromUsageStore.claudeSwapAccountSnapshots, merged byclaude-swap:<slot>, only when the email still matches.slot:Nwhen there is no email). Replacing the account in that slot, or a legacy cache row with no discriminator, does not reuse the previous 100% bars.resetsAtis already in the past from both retained snapshots and directly attachedunavailableusage objects. Keep remaining exhausted windows. If none are still exhausted, show "Polling deferred until a limit resets." instead of resurrecting expired 100% bars.UsageFormatter.resetLine.token_expired,relogin_required,api_key,keychain_unavailable,no_credentials, unknown) are unchanged.claude-swap:<slot>. Email is display-only. No Keychain.Verification
swift test --filter ClaudeSwapAccountProjectionTests --filter ClaudeProviderRuntimeTests— 25 passed, including staggered-reset cases (expired session + still-exhausted weekly; all-expired → deferred note).ClaudeProviderRuntimeTestsusesDate()-relative reset timestamps.codexbar cards --provider claude --no-colorfrom this branch), 2026-08-19.cswap --list --jsonschemaVersion 1, 2 accounts, bothusageStatus: "ok"with usage present (the deferredunavailablepath is not live on this machine right now). Cards render both slots with session/weekly bars and do not show "Usage fetch failed.":unavailablewith omitted windows.